// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "SubcaseService.h"

#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Input/Solver/Subcase.h"

#include "DBManager/Common/ServiceMacro.h"
#include "DBManager/IService/Input/Load/IDLOADService.h"
#include "DBManager/IService/Input/Load/ILoadCombinationService.h"
#include "DBManager/IService/Input/Load/ILoadSummaryService.h"

using namespace SG::DBManager;
using namespace SG::DataStructure;
using namespace SG::DataStructure::FEM;
// 注册服务
SERVICE_REG_WITH_DBM_IMPL (SubcaseService, ISubcaseRepository)

SubcaseService::SubcaseService (DBServiceFactory* const dbServiceFactory, ISubcaseRepository& repos)
    : m_repository (repos), m_SerFactory (dbServiceFactory)
{}

SubcaseService::~SubcaseService ()
{}

void SubcaseService::Initial (SG::Utility::SGParameter entity)
{
    m_upToDate = false;
    return m_repository.Initial (entity);
}

SG::Utility::SGParameter SubcaseService::GetSubcase ()
{
    if (!m_upToDate)
    {
        m_data     = m_repository.GetSubcase ();
        m_upToDate = true;
    }
    return m_data;
}

std::vector<SG::DataStructure::Common::Id> SubcaseService::GetAllSubcaseID ()
{
    if (!m_upToDate)
    {
        m_data     = m_repository.GetSubcase ();
        m_upToDate = true;
    }
    std::vector<SG::DataStructure::Common::Id> returnIds;
    for (auto iter = m_data.begin (); iter != m_data.end (); iter++)
    {
        returnIds.push_back (std::stoll (iter.name ()));
    }
    // 排序
    std::sort (returnIds.begin (), returnIds.end ());
    return returnIds;
}

SG::Utility::SGParameter SubcaseService::FindSubCase (SG::DataStructure::Common::Id subcaseId)
{
    if (!m_upToDate)
    {
        m_data     = m_repository.GetSubcase ();
        m_upToDate = true;
    }
    std::string strID = std::to_string (subcaseId);
    bool        isHas = m_data.Has (strID);
    if (isHas)
    {
        return m_data[strID];
    }
    throw std::runtime_error ("SubcaseService::FindSubCase has bad subcaseId:" + strID);
}

/// @brief 递归获取某个Load的子集
void GetLoadset (Common::Id loadId, DBServiceFactory* const dbServiceFactory, std::set<Common::Id>& loadset)
{
    // 获取LoadSummaryService
    auto                                loadSummaryService = dbServiceFactory->get<ILoadSummaryService> ();
    SG::DataStructure::FEM::LoadTypeSet loadType;
    try
    {
        loadType = loadSummaryService->GetLoadType (loadId);
    }
    catch (const std::exception& e)
    {
        SGError << "SubcaseService::GetLoadset: " << e.what ();
        return;
    }

    loadset.insert (loadId);

    // 对于DLOAD或LOAD一定是第一个
    if (loadType.find (FEM::LoadType::LOAD_LOAD) != loadType.end ())
    {
        auto ser = dbServiceFactory->get<ILoadCombinationService> ();

        FEM::LoadCombination loadData;
        ser->FindById (loadId, loadData);
        for (auto& item : loadData.m_Items)
        {
            GetLoadset (item.m_subSet, dbServiceFactory, loadset);
        }
    }
}

std::set<Common::Id> SubcaseService::GetLoadsetIds (const std::vector<Common::Id>& subcaseId)
{
    if (!m_upToDate)
    {
        m_data     = m_repository.GetSubcase ();
        m_upToDate = true;
    }
    std::set<Common::Id> loadIds;
    try
    {
        for (auto id : subcaseId)
        {
            // 判断传入参数是否合理
            std::string strId = std::to_string (id);
            bool        isHas = m_data.Has (strId);
            if (!isHas)
            {
                throw std::runtime_error ("SubcaseService::GetLoadsetIds has bad subcaseId:" + strId);
            }
            auto       subcase = m_data[strId];  // 某个subcase的parametrer
            Common::Id loadID  = 0;              // 记录loadID
            // 假设只对LOAD与DLOAD处理，暂时不知道还有其他可能
            bool hasLoad  = subcase.Has ("LOAD");
            bool hasDLoad = subcase.Has ("DLOAD");
            // LOAD与DLoad都不存在,跳过该subcase
            if ((!hasLoad) && (!hasDLoad))
            {
                continue;
            }
            hasLoad ? loadID = std::stoll (subcase["LOAD"]["MAIN_KEY"].GetString ())
                    : loadID = std::stoll (subcase["DLOAD"]["MAIN_KEY"].GetString ());
            // 获取LoadSummaryService，获取LoadType
            auto                                loadSummaryService = m_SerFactory->get<ILoadSummaryService> ();
            SG::DataStructure::FEM::LoadTypeSet loadType;
            try
            {
                loadType = loadSummaryService->GetLoadType (loadID);
            }
            catch (const std::exception& e)
            {
                SGError << "SubcaseService::GetLoadsetIds: " << e.what ();
                loadIds.insert (loadID);
                return loadIds;
            }

            // 对于DLOAD或LOAD一定是第一个
            if (loadType.find (FEM::LoadType::LOAD_LOAD) != loadType.end ())
            {
                std::set<Common::Id> loadset;
                GetLoadset (loadID, m_SerFactory, loadset);
                loadIds.insert (loadset.begin (), loadset.end ());
            }
            else if (loadType.find (FEM::LoadType::LOAD_DLOAD) != loadType.end ())
            {
                auto           ser = m_SerFactory->get<IDLOADService> ();
                FEM::DLOADData dloadData;
                ser->FindBySId (loadID, dloadData);
                for (auto& item : dloadData.m_SLList)
                {
                    loadIds.insert (item.m_LI);
                }
            }
            else
            {
                loadIds.insert (loadID);
            }
        }
    }
    catch (const std::exception& e)
    {
        SGError << e.what ();
    }

    return loadIds;
}

SG::DataStructure::Common::Status SubcaseService::CopyData (DBServiceFactory* const dest)
{
    dest->get<ISubcaseService> ()->Initial (m_repository.GetSubcase ());

    return SG::DataStructure::Common::Status::STATUS_Success;
}

SOLType SubcaseService::GetSOLType (SG::DataStructure::Common::Id subcaseId)
{
    try
    {
        auto p = FindSubCase (subcaseId);
        return SG::DataStructure::FEM::Subcase (p).GetSOLType ();
    }
    catch (const std::runtime_error& e)
    {
        return SOLType::SOL_UNKNOWN;
    }
}
